/*  Copyright (C) 2008  Alexander Blyzniuchenko (BlezAlex)

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

using System;
using System.Collections.Generic;
using System.Text;

namespace DC.Http
{
    public class HttpUtility
    {
        private readonly static List<char> ReservedCharacters = new List<char>(new char[] { '$', '&', '+', ',', '/', ':', ';', '=', '?', '@' });
        private readonly static List<char> UnsafeCharacters = new List<char>(new char[] { ' ', '<', '>', '#', '%', '{', '}', '|', '\\', '^', '~', '[', ']', '`' });

        public static string DecodeURL(string url)
        {
            url = url.Replace("+", " ");
            byte[] source = Encoding.UTF8.GetBytes(url);
            byte[] result = new byte[source.Length];
            int curResultPos = 0;
            for (int i = 0; i < source.Length; i++)
            {
                if (source[i] == '%' && i + 2 < source.Length)
                {
                    i++;
                    int code = HexToInt(source[i]) * 16;
                    i++;
                    code += HexToInt(source[i]);
                    result[curResultPos++] = (byte)code;
                }
                else
                    result[curResultPos++] = source[i];
            }
            return Encoding.UTF8.GetString(result, 0, curResultPos).Trim('\0');
        }

        public static string EncodeURL(string url)
        {
            StringBuilder result = new StringBuilder(url.Length * 2);
            byte[] source = Encoding.UTF8.GetBytes(url);
            foreach (byte curChar in source)
            {
                if (
                        curChar < 31 || curChar == 127 || //ASCII Control characters. Why:  These characters are not printable.
                        curChar >= 128 || // Non-ASCII characters. Why: These are by definition not legal in URLs since they are not in the ASCII set.
                        ReservedCharacters.Contains((char)curChar) ||
                        UnsafeCharacters.Contains((char)curChar)
                    )
                {
                    result.Append(EncodeChar(curChar));
                }
                else
                    result.Append((char)curChar);
            }
            return result.ToString();
        }

        public static string GetRelaivePath(string url)
        {
            const string protoData = "://";

            if (url.StartsWith("/"))
                return url;

            int proto = url.IndexOf(protoData);
            if (proto < 0)
                throw new ArgumentException("Url does not contain '://' text.");

            int relPathBegin = url.IndexOf("/", proto + protoData.Length);
            if (relPathBegin < 0)
                return "/";

            return url.Substring(relPathBegin);
        }

        public static string ConcatPath(string a, string b)
        {
            return a.TrimEnd('/') + "/" + b.TrimStart('/');
        }

        public static string GetFileName(string filePath)
        {
            int slashPos = filePath.LastIndexOf(DcDirectory.PATH_SEPARATOR);
            return slashPos >= 0 ? filePath.Substring(slashPos + 1) : filePath;
        }

        public static string GetPath(string filePath)
        {
            int slashPos = filePath.LastIndexOf(DcDirectory.PATH_SEPARATOR);
            return slashPos >= 0 ? filePath.Substring(0, slashPos) : filePath;
        }

        private static string EncodeChar(byte character)
        {
            return "%" + string.Format("{0:x}", character);
        }

        private static int HexToInt(byte h)
        {
            if ((h >= '0') && (h <= '9'))
            {
                return (h - '0');
            }
            if ((h >= 'a') && (h <= 'f'))
            {
                return ((h - 'a') + 10);
            }
            if ((h >= 'A') && (h <= 'F'))
            {
                return ((h - 'A') + 10);
            }
            return -1;
        }
    }
}